﻿using YNTK.Common.Core.Manager;
using YNTK.Common.Enum;
using YNTK.Common.Extension;
using YNTK.Common.Filter;
using YNTK.Dependency;
using YNTK.DynamicApiController;
using YNTK.FriendlyException;
using YNTK.JsonSerialization;
using YNTK.LinqBuilder;
using YNTK.Message.Entitys;
using YNTK.Message.Entitys.Dto.Message;
using YNTK.Message.Extensions;
using YNTK.Message.Interfaces.Message;
using YNTK.System.Entitys.Permission;
using YNTK.System.Interfaces.Permission;
using Mapster;
using Microsoft.AspNetCore.Mvc;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Yitter.IdGenerator;
using YNTK.Data.MongoDB.Repositorie;
using YNTK.System.Interfaces.Common;
using YNTK.System.Entitys.Dto.Common;
using Shipeng.Util;
using Microsoft.AspNetCore.Http;
using YNTK.Common.Const;
using System.Linq.Expressions;
using MongoDB.Driver;
using System.ComponentModel.DataAnnotations;

namespace YNTK.Message.Service
{
    /// <summary>
    /// 系统消息服务的实现
    /// 版 本：V1.0.0
    /// 版 权：云南通科科技有限公司（https://www.yntkkj.com）
    /// 作 者：李仕鹏
    /// 日 期：2022-10-23 
    /// </summary>
    [ApiDescriptionSettings(Tag = "系统消息服务", Name = "message", Order = 789)]
    [Route("api/[controller]")]
    public class MessageService : IMessageService, IDynamicApiController, ITransient
    {
        private readonly ISqlSugarRepository<MessageEntity> _messageRepository;//消息sqlSugar仓储
        private readonly IMongoDBRepository<MessageEntity> _messageMongoDbRepository;//消息mongodb仓储
        private readonly ISqlSugarRepository<MessageReceiveEntity> _messageReceiveRepository;//消息接收sqlSugar仓储
        private readonly IMongoDBRepository<MessageReceiveEntity> _messageReceiveMongoDbRepository;//消息接收mongodb仓储
        private readonly ISqlSugarRepository<MessageFileEntity> _messageFileRepository;//消息相关附件sqlSugar仓储
        private readonly IMongoDBRepository<MessageFileEntity> _messageFileMongoDbRepository;//消息相关附件mongodb仓储

        private readonly SqlSugarScope db;
        private readonly IUserManager _userManager;
        private readonly ITkUsersService _tkUsersService;//用户服务
        private readonly IOrganizeService _organizeService;//组织服务
        private readonly IMechanismService _mechanismService;//机构服务
        private readonly IFileService _fileService;//文件服务
        private readonly HttpContext _httpContext;

        private readonly string _message = "base_message";//mongodb中消息数据集名称
        private readonly string _messagereceive = "base_messagereceive";//mongodb中消息接收数据集名称
        private readonly string _messagefiles = "base_messagefiles";//mongodb中消息相关附件数据集名称

        /// <summary>
        /// 构造方法依赖注入
        /// </summary>
        /// <param name="messageRepository">消息sqlSugar仓储</param>
        /// <param name="messageMongoDbRepository">消息mongodb仓储</param>
        /// <param name="messageReceiveRepository">消息接收sqlSugar仓储</param>
        /// <param name="messageReceiveMongoDbRepository">消息接收mongodb仓储</param>
        /// <param name="messageFileRepository">消息相关附件sqlSugar仓储</param>
        /// <param name="messageFileMongoDbRepository">消息相关附件mongodb仓储</param>
        /// <param name="userManager"></param>
        /// <param name="tkUsersService">用户服务</param>
        /// <param name="organizeService">组织服务</param>
        /// <param name="mechanismService">机构服务</param>
        /// <param name="fileService">文件服务</param>
        public MessageService(ISqlSugarRepository<MessageEntity> messageRepository,
            IMongoDBRepository<MessageEntity> messageMongoDbRepository,
            ISqlSugarRepository<MessageReceiveEntity> messageReceiveRepository,
            IMongoDBRepository<MessageReceiveEntity> messageReceiveMongoDbRepository,
            ISqlSugarRepository<MessageFileEntity> messageFileRepository,
            IMongoDBRepository<MessageFileEntity> messageFileMongoDbRepository,
            IUserManager userManager, ITkUsersService tkUsersService,
            IOrganizeService organizeService, IMechanismService mechanismService,
            IFileService fileService)
        {
            _messageRepository = messageRepository;
            _messageMongoDbRepository = messageMongoDbRepository;
            _messageReceiveRepository = messageReceiveRepository;
            _messageReceiveMongoDbRepository = messageReceiveMongoDbRepository;
            _messageFileRepository = messageFileRepository;
            _messageFileMongoDbRepository = messageFileMongoDbRepository;

            db = messageRepository.Context;
            _userManager = userManager;
            _tkUsersService = tkUsersService;
            _organizeService = organizeService;
            _mechanismService = mechanismService;
            _fileService = fileService;
            _httpContext = App.HttpContext;
        }


        /// <summary>
        /// 获取通知公告接收对象类型
        /// </summary>
        /// <returns></returns>
        [HttpGet("receivetypes")]
        public TkResult<List<EnumListDto>> GetNoticeTypeList()
        {
            Dictionary<int, string> dic = EnumHelper.EnumToDic<NoticeEnum>();
            var result = new List<EnumListDto>();
            foreach (KeyValuePair<int, string> kv in dic)
            {
                result.Add(new EnumListDto { Id = kv.Key.ToStr(), Value = kv.Key, Description = kv.Value });
            }
            return TkResult<List<EnumListDto>>.Success(result);
        }

        /// <summary>
        /// 获取消息类型
        /// </summary>
        /// <returns></returns>
        [HttpGet("messagetypes")]
        public TkResult<List<EnumListDto>> GetMessageTypeList()
        {
            Dictionary<int, string> dic = EnumHelper.EnumToDic<MessageTypeEnum>();
            var result = new List<EnumListDto>();
            foreach (KeyValuePair<int, string> kv in dic)
            {
                result.Add(new EnumListDto { Id = kv.Key.ToStr(), Value = kv.Key, Description = kv.Value });
            }
            return TkResult<List<EnumListDto>>.Success(result);
        }

        #region 通知公告
        /// <summary>
        /// 分页获取通知公告数据
        /// </summary>
        /// <param name="query">查询通知公告请求模型</param>
        /// <returns></returns>
        [HttpPost("notice/gets")]
        public async Task<TkPageResult<MessageListDto>> Gets([FromBody] QueryMessageFilterRequestModle query)
        {
            try
            {
                var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
                string userId = user.Value;
                string organizeId = user.Subject.FindFirst(ClaimConst.ORGANIZEID).Value;
                string mechanismId = user.Subject.FindFirst(ClaimConst.MECHANISMID).Value;
                string roleId = user.Subject.FindFirst(ClaimConst.ROLEID).Value;
                //账号类型【0.平台运营人员 1.超级管理员 2.组织管理员 3.组织用户 4.第三方登录用户 5.游客用户】
                var authenticationType = user.Subject.FindFirst(ClaimConst.ACCOUNTTYPE).Value;

                #region 拼接查询条件
                Expression<Func<MessageReceiveEntity, bool>> where = m => 
                //当前登录用户发起的
                (!m.IsReceive && m.SendUserId == userId) ||
                //当前登录用户接收的
                (m.IsReceive && m.UserId== userId);
                if (!string.IsNullOrWhiteSpace(query.mechanismId))
                {
                    string queryMechanismId = await _mechanismService.GetIdAsync(query.mechanismId, organizeId);
                    where = where.And(m => m.MechanismId == queryMechanismId);
                }
                if (query.type != null) where = where.And(m=>m.Type==query.type.GetHashCode());
                if (query.notice != null) where = where.And(m => m.Notice == query.notice.GetHashCode());
                if (query.isRead != null)
                    where = where.And(m => m.UserId == userId && m.IsReceive && m.IsRead == query.isRead);
                if (query.startTime != null) where = where.And(m => m.CreatorTime >= query.startTime);
                if (query.endTime != null) where = where.And(m => m.CreatorTime <= query.endTime);
                if (!string.IsNullOrWhiteSpace(query.keyword))
                    where = where.And(m => m.Title.Contains(query.keyword));
                #endregion

                var pageList = new SqlSugarPagedList<MessageListDto>();

                #region 先从mongodb中获取通知公告数据
                //排序生成器
                var builderSort = Builders<MessageReceiveEntity>.Sort;
                //排序约束   Ascending 正序    Descending 倒序
                var sort = builderSort.Descending(r => r.CreatorTime);
                //Item1.结果集 Item2.总条数 Item3.总页数
                (List<MessageReceiveEntity>, int, int) result =
                    await _messageReceiveMongoDbRepository.GetListAsync(_messagereceive,
                    where, query.currentPage, query.pageSize, null, sort);
                pageList.list = result.Item1.Adapt<List<MessageListDto>>();
                pageList.pagination = new PagedModel()
                {
                    PageIndex = query.currentPage,
                    PageSize = query.pageSize,
                    Total = result.Item2,
                    PageCount = result.Item3
                };
                #endregion

                if (!pageList.list.Any())
                {
                    #region 再从sqlserver中获取通知公告数据
                    var sqlResult = await _messageReceiveRepository.Entities.Where(where)
                        .OrderBy(r => r.CreatorTime, OrderByType.Desc)
                        .ToPagedListAsync(query.currentPage, query.pageSize);
                    pageList.list = sqlResult.list.Adapt<List<MessageListDto>>();
                    pageList.pagination = sqlResult.pagination;
                    #endregion
                }

                #region 处理通知公告返回数据
                if (pageList.list.Any())
                {
                    var mechanismIds = pageList.list.Where(r => !string.IsNullOrWhiteSpace(r.mechanismId))
                        ?.Select(r => r.mechanismId.Split(',').ToList())
                        ?.SelectMany(r => r).Distinct().ToList();
                    var mechanisms = !mechanismIds.Any() ? new List<MechanismEntity>() :
                        await _mechanismService.GetMechanismListAsync(null, mechanismIds);                    
                    var messageIds = pageList.list.Select(r => r.messageId).ToList();
                    var messgaeList = await GetMessageListAsync(r=> messageIds.Contains(r.Id));
                    var entity = new MessageEntity();
                    var userIds = messgaeList.Select(r => r.CreatorUserId).Distinct().ToList();
                    var users = await _tkUsersService.GetUserListByIds(userIds);
                    pageList.list.ForEach(message =>
                    {
                        entity = messgaeList.FirstOrDefault(r => r.Id == message.messageId);
                        message.typeText = EnumHelper.GetEnumDescriptionString
                        (message.type, typeof(MessageTypeEnum));
                        message.noticeText = EnumHelper.GetEnumDescriptionString
                        (message.notice, typeof(NoticeEnum));
                        if (message.isReceive)//当前消息为接收
                            message.stateText = message.isRead ? "已读" : "未读";
                        else//当前消息为发送
                        {                         
                            if (entity.CreatorUserId == message.sendUserId)
                            {
                                int count = (int)entity.ToUserCount - (int)entity.ReadUserCount;
                                message.stateText = count > 0 ? $"{count}人未读" : "已读";
                            }
                        }
                        if (!string.IsNullOrWhiteSpace(message.mechanismId))
                        {
                            message.mechanismName = string.Join('/', mechanisms
                                ?.Where(r => message.mechanismId.Split(',').ToList().Contains(r.Id))
                                ?.Select(r => r.Name)?.ToList()).Split('/').Last();
                        }
                        message.sendUserName = users?.FirstOrDefault(r => r.Id == entity.CreatorUserId)?.RealName;
                    });
                }
                #endregion

                return TkPageResult<MessageListDto>.Success(pageList);
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"分页获取通知公告数据发生异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 获取通知公告详细信息
        /// </summary>
        /// <param name="messageId">消息id</param>
        /// <returns></returns>
        [HttpGet("notice/get/{messageId}")]
        public async Task<TkResult<MessageDto>> Get([Required] string messageId)
        {
            try
            {
                var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
                string userId = user.Value;

                var entity = await GetMessageInfoAsync(r=>r.Id== messageId);
                _ = entity ?? throw YNTKException.Oh(ErrorCode.D7011);
                Expression<Func<MessageReceiveEntity, bool>> where = m => m.MessageId == messageId;
                if (entity.CreatorUserId == userId) where = where.And(m => m.SendUserId == userId && !m.IsReceive);
                else where = where.And(m=>m.UserId==userId && m.IsReceive);
                var receive = await GetMessageReceiveAsync(where);
                _ = receive ?? throw YNTKException.Oh(ErrorCode.D7011);
                var message = receive.Adapt<MessageDto>();

                #region 处理通知公告返回信息
                message.typeText = EnumHelper.GetEnumDescriptionString
                      (message.type, typeof(MessageTypeEnum));
                message.noticeText = EnumHelper.GetEnumDescriptionString
                (message.notice, typeof(NoticeEnum));
                if (message.isReceive)//当前消息为接收
                    message.stateText ="已读";
                else//当前消息为发送
                {
                    if (entity.CreatorUserId == message.sendUserId)
                    {
                        int count = (int)entity.ToUserCount - (int)entity.ReadUserCount;
                        message.stateText = count > 0 ? $"{count}人未读" : "已读";
                    }
                }
                if (!string.IsNullOrWhiteSpace(message.mechanismId))
                {
                    message.mechanismName = string.Join('/', (await _mechanismService
                        .GetMechanismListAsync("",message.mechanismId.Split(',').ToList())
                        )?.Select(r => r.Name)?.ToList()).Split('/').Last();
                }
                message.sendUserName = (await _tkUsersService.GetUserInfoByUserId(entity.CreatorUserId))?.RealName;

                if (entity.Notice == 2)
                {
                    //获取通知公告接收人
                    var receiveUsers = await GetMessageReceiveListAsync(r => r.MessageId == messageId && r.IsReceive);
                    message.toUserIds = receiveUsers.Select(r => r.UserId).Distinct().ToList();
                    var users = await _tkUsersService.GetUserListAsync(r => message.toUserIds.Contains(r.Id) && r.DeleteMark == null);
                    if (users.Any()) message.toUserNames = string.Join(',', users.Select(r => r.RealName).ToList());
                }
                if (entity.Notice == 3 && !string.IsNullOrWhiteSpace(entity.ToMechanismValue))
                {
                    var mechanismIds = entity.ToMechanismValue.Split(';').Select(r => r.Split(',').Last()).ToList();
                    var mechanisms = await _mechanismService.GetMechanismListAsync("", mechanismIds);
                    if(mechanisms.Any()) message.toMechanismNames =string.Join(',', mechanisms.Select(r=>r.Name).ToList());
                    message.toMechanismValue = entity.ToMechanismValue.Split(';').Select(r=>r.Split(',')).ToList();
                }
                //获取访客记录相关附件数据
                var fileData = await GetMessageFileListAsync(messageId);
                message.fileData = fileData.Adapt<List<CommonFileListDto>>();
                message.bodyText = entity.BodyText;//正文
                #endregion

                #region 修改阅读量
                entity.ReadCount = entity.ReadCount + 1;//阅读数量+1
                if (message.isReceive)//当前登录用户为消息接收人
                {
                    receive.IsRead = true;
                    receive.ReadCount = receive.ReadCount + 1;
                    receive.ReadTime = DateTime.Now;//阅读时间
                    await _messageReceiveRepository.Context.Updateable(receive)
                    .WhereColumns(it => new { it.Id }).ExecuteCommandAsync();
                    await _messageReceiveMongoDbRepository.UpdateAsync(receive, _messagereceive, m => m.Id == receive.Id);

                    entity.ReadUserCount = (int)await GetCountAsync(r => r.MessageId == messageId &&
                    r.IsReceive && r.IsRead);//已阅读用户数量
                }
                await _messageRepository.Context.Updateable(entity)
                      .IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync();
                await _messageMongoDbRepository.UpdateAsync(entity, _message, m => m.Id == entity.Id);
                #endregion

                return TkResult<MessageDto>.Success(message);
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"获取通知公告详细信息发生异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 添加通知公告
        /// </summary>
        /// <param name="input">添加通知公告请求模型</param>
        /// <returns></returns>
        [HttpPost("notice/add")]
        public async Task Create([FromBody] AddMessageRequestModel input)
        {
            try
            {
                var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
                string userId = user.Value;
                string organizeId = user.Subject.FindFirst(ClaimConst.ORGANIZEID).Value;
                string mechanismId = user.Subject.FindFirst(ClaimConst.MECHANISMID).Value;
                string roleId = user.Subject.FindFirst(ClaimConst.ROLEID).Value;
                //账号类型【0.平台运营人员 1.超级管理员 2.组织管理员 3.组织用户 4.第三方登录用户 5.游客用户】
                var authenticationType = user.Subject.FindFirst(ClaimConst.ACCOUNTTYPE).Value;
                if (authenticationType == "4" || authenticationType == "5")
                    throw YNTKException.Oh(ErrorCode.D1016);
                if(input.notice== NoticeEnum.User && (input.toUserIds==null || input.toUserIds.Count<=0))
                    throw YNTKException.Oh(ErrorCode.D7005);
                if(input.notice == NoticeEnum.Mechanism && (input.toMechanismValue == null || input.toMechanismValue.Count<=0))
                    throw YNTKException.Oh(ErrorCode.D7018);

                #region 判断是否有可接收消息的人员
                var mechanismIds = new List<string>();
                Expression<Func<UserEntity, bool>> where = u => u.EnabledMark == 1 && u.DeleteMark == null;
                if (input.notice != NoticeEnum.User)
                {
                    if (input.notice == NoticeEnum.Owner)
                    {
                        if (authenticationType == "2" || authenticationType == "3")
                            where = where.And(u => u.OrganizeId == organizeId);
                    }
                    else if (input.notice == NoticeEnum.Agency) where = where.And(u => u.MechanismId == mechanismId);
                    else if (input.notice == NoticeEnum.Mechanism)//特定机构
                    {
                        mechanismIds = input.toMechanismValue.Select(r => string.Join(',', r)).Distinct().ToList();
                        where = where.And(u => mechanismIds.Contains(u.MechanismId));
                    }
                    else where = where.And(u=>1==2);
                }
                else where = where.And(u=> input.toUserIds.Contains(u.Id));
                where = where.And(u=>u.Id!= userId);
                var users = await _tkUsersService.GetUserListAsync(where);
                if(!users.Any()) throw YNTKException.Oh(ErrorCode.D7006);
                input.toUserIds = users.Select(r => r.Id).ToList();
                #endregion

                var entity = new MessageEntity();
                entity.Title = input.title;
                entity.Notice = input.notice.GetHashCode();//通知公告接收对象类型(0.所有人 1.本机构 2.指定人员)
                //消息类型(0.平台公告 1.通知公告 2.系统消息 3.私信消息)
                entity.Type = authenticationType == "2" || authenticationType == "3" ? 1 : 0;
                entity.OrganizeId = organizeId;
                entity.MechanismId = mechanismId;
                entity.ToUserCount = input.toUserIds.Count();//收件用户数量
                if (input.notice == NoticeEnum.User)
                    entity.ToUserIds = string.Join(',', input.toUserIds);//收件用户id,多个用户按逗号分割
                if (input.notice == NoticeEnum.Mechanism)
                    entity.ToMechanismValue = string.Join(';', mechanismIds);//收件机构id,多个机构按逗号分割
                entity.IsRead = false;//是否阅读
                entity.BodyText = input.bodyText;
                entity.ReadCount = 0;//阅读次数
                entity.ReadUserCount = 0;//已阅读用户数量

                //保存通知公告到sqlserver
                var isOk = await _messageRepository.Context.Insertable(entity)
                   .CallEntityMethod(m => m.Creator()).ExecuteReturnEntityAsync();
                _ = isOk ?? throw YNTKException.Oh(ErrorCode.D7003);

                //保存通知公告到mongodb
                entity = isOk;              
                var result = await _messageMongoDbRepository.AddAsync(entity, _message);
                if (!result) throw YNTKException.Oh(ErrorCode.D7004);

                //保存通知公告接收用户             
                await SaveMessageReceiveAsync(entity, input.toUserIds);
                //保存通知公告相关附件
                await SaveMessageFileAsync(entity,input.fileData);
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"添加通知公告发生异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 删除通知公告
        /// </summary>
        /// <param name="messageId">消息id</param>
        /// <returns></returns>
        [HttpDelete("notice/delete/{messageId}")]
        public async Task Delete([Required] string messageId)
        {
            try
            {
                var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
                string userId = user.Value;

                var entity = await GetMessageInfoAsync(r => r.Id == messageId);
                _ = entity ?? throw YNTKException.Oh(ErrorCode.D7011);
                Expression<Func<MessageReceiveEntity, bool>> where = m => m.MessageId == messageId;
                if (entity.CreatorUserId == userId) where = where.And(m => m.SendUserId == userId && !m.IsReceive);
                else where = where.And(m => m.UserId == userId && m.IsReceive);
                var receive = await GetMessageReceiveAsync(where);
                _ = receive ?? throw YNTKException.Oh(ErrorCode.D7011);

                if(entity.CreatorUserId== userId)//当前登录用户为发起人
                {
                    //删除消息
                    var isOk = await _messageRepository.Context.Deleteable(entity).ExecuteCommandAsync();
                    if (!(isOk > 0)) throw YNTKException.Oh(ErrorCode.D7014);
                    var delete = await _messageMongoDbRepository.DeleteAsync(_message, m => m.Id == entity.Id);
                    if (!(delete > 0)) throw YNTKException.Oh(ErrorCode.D7015);
                    //删除接收用户
                    await DeleteMessageReceiveAsync(messageId);
                    //删除消息附件
                    await DeleteMessageFileAsync(messageId);
                }
                else//当前登录用户为接收人
                {
                    //只删除自己的接收消息
                    var isOK = await _messageReceiveRepository.DeleteAsync(r => r.Id == receive.Id);
                    if (!(isOK > 0)) throw YNTKException.Oh(ErrorCode.D7012);
                    var delete = await _messageReceiveMongoDbRepository.DeleteAsync(_messagereceive, m => m.Id == receive.Id);
                    if (!(delete > 0)) throw YNTKException.Oh(ErrorCode.D7013);
                }
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"删除通知公告发生异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 获取当前登录用户未读消息数量
        /// </summary>
        /// <returns></returns>
        [HttpGet("notice/unreadcount")]
        public async Task<TkResult<long>> GetUserUnreadCount()
        {
            try
            {
                var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
                string userId = user.Value;
                long count = await GetCountAsync(m => m.UserId == userId && m.IsReceive && !m.IsRead);
                return TkResult<long>.Success(count);
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"获取当前登录用户未读消息数量发生异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 全部已读
        /// </summary>
        /// <returns></returns>
        [HttpPut("notice/messageread")]
        public async Task AllRead()
        {
            try
            {
                db.BeginTran();
                var unread = await GetMessageReceiveListAsync(m => m.UserId == _userManager.UserId && m.IsReceive && !m.IsRead);
                if (unread.Any())
                {
                    var messageIds = unread.Select(r => r.MessageId).Distinct().ToList();
                    var messageList = await GetMessageListAsync(r => messageIds.Contains(r.Id));
                    var entities = new List<MessageEntity>();
                    var entity = new MessageEntity();
                    unread.ForEach(read =>
                    {
                        read.IsRead = true;//是否阅读
                        read.ReadTime = DateTime.Now;//阅读时间
                        read.ReadCount = read.ReadCount + 1;//阅读次数

                        entity = messageList.FirstOrDefault(r => r.Id == read.MessageId);
                        entity.ReadCount = entity.ReadCount + 1;//阅读数量+1
                        entity.ReadUserCount = entity.ReadUserCount + 1;//已阅读用户数量+1
                        entities.Add(entity);
                    });
                    await _messageReceiveRepository.Context.Updateable(unread)
                    .WhereColumns(it => new { it.Id }).ExecuteCommandAsync();
                    await _messageReceiveMongoDbRepository.UpdateManayAsync(unread, _messagereceive);

                    await _messageRepository.Context.Updateable(entities)
                      .WhereColumns(it => new { it.Id }).ExecuteCommandAsync();
                    await _messageMongoDbRepository.UpdateManayAsync(entities, _message);
                }
                db.CommitTran();
            }
            catch (Exception)
            {
                db.RollbackTran();
            }
        }

        /// <summary>
        /// 清空消息(全部删除,包括自己发送的和自己接收的)
        /// </summary>
        /// <returns></returns>
        [HttpDelete("notice/clear")]
        public async Task Clear()
        {
            try
            {
                db.BeginTran();
                Expression<Func<MessageReceiveEntity, bool>> where = m =>
                //当前登录用户发起的
                (!m.IsReceive && m.SendUserId == _userManager.UserId) ||
                //当前登录用户接收的
                (m.IsReceive && m.UserId == _userManager.UserId);
                var list = await GetMessageReceiveListAsync(where);
                if (list.Any())
                {
                    //当前登录用户接收的信息
                    var receives = list.Where(r => r.IsReceive && r.UserId == _userManager.UserId)?.ToList();
                    //当前登录用户发送的消息
                    var sends = list.Where(r => !r.IsReceive && r.SendUserId == _userManager.UserId)?.ToList();
                    if (receives.Any())
                    {
                        //只删除自己的接收消息
                        var receiveIds = receives.Select(r => r.Id).ToList();
                        await _messageReceiveRepository.DeleteAsync(r => receiveIds.Contains(r.Id));
                        await _messageReceiveMongoDbRepository.DeleteAsync(_messagereceive,m=> receiveIds.Contains(m.Id));
                    }
                    if (sends.Any())
                    {
                        //删除消息
                        var messageIds = sends.Select(r => r.MessageId).Distinct().ToList();
                        await _messageRepository.DeleteAsync(r=> messageIds.Contains(r.Id));
                        await _messageMongoDbRepository.DeleteAsync(_message, m => messageIds.Contains(m.Id));
                        //删除接收用户
                        await DeleteMessageReceiveAsync(m => messageIds.Contains(m.MessageId));
                        //删除消息附件
                        await DeleteMessageFileAsync(m=> messageIds.Contains(m.MessageId));
                    }
                }
                db.CommitTran();
            }
            catch (Exception)
            {
                db.RollbackTran();
            }
        }

        /// <summary>
        /// 根据条件获取通知公告信息
        /// </summary>
        /// <param name="where">条件</param>
        /// <returns></returns>
        [NonAction]
        public async Task<MessageEntity> GetMessageInfoAsync(Expression<Func<MessageEntity, bool>> where)
        {
            var entity = await _messageMongoDbRepository.GetAsync(_message, where);
            if (entity == null) entity = await _messageRepository.FirstOrDefaultAsync(where);
            return entity;
        }

        /// <summary>
        /// 根据条件获取通知公告数据
        /// </summary>
        /// <param name="where">条件</param>
        /// <returns></returns>
        [NonAction]
        public async Task<List<MessageEntity>> GetMessageListAsync(Expression<Func<MessageEntity, bool>> where)
        {
            //从mongodb中获取通知公告数据
            var result = await _messageMongoDbRepository.GetListAsync(_message, where);
            if (!result.Any())
            {
                //从sqlserver数据库中获取通知公告数据
                result = await _messageRepository.Entities.Where(where).ToListAsync();
            }
            return result;
        }
        #endregion


        #region 消息相关附件
        /// <summary>
        /// 获取消息相关附件数据
        /// </summary>
        /// <param name="messageId">消息id</param>
        /// <returns></returns>
        private async Task<List<MessageFileEntity>> GetMessageFileListAsync(string messageId)
        {
            //从mongodb中获取附件数据
            var result = await _messageFileMongoDbRepository.GetListAsync(_messagefiles, r => r.MessageId == messageId);
            if (!result.Any())
            {
                //从sqlserver数据库中获取附件数据
                result = await _messageFileRepository.Entities
                    .Where(r => r.MessageId == messageId).ToListAsync();
            }
            return result;
        }

        /// <summary>
        /// 根据条件获取消息相关附件
        /// </summary>
        /// <param name="where"></param>
        /// <returns></returns>
        private async Task<List<MessageFileEntity>> GetMessageFileListAsync(Expression<Func<MessageFileEntity, bool>> where)
        {
            //从mongodb中获取附件数据
            var result = await _messageFileMongoDbRepository.GetListAsync(_messagefiles, where);
            if (!result.Any())
            {
                //从sqlserver数据库中获取附件数据
                result = await _messageFileRepository.Entities.Where(where).ToListAsync();
            }
            return result;
        }

        /// <summary>
        /// 保存消息相关附件
        /// </summary>
        /// <param name="entity">消息信息</param>
        /// <param name="fileData">附件数据</param>
        /// <returns></returns>
        private async Task SaveMessageFileAsync(MessageEntity entity, List<CommonFileRequestModel> fileData)
        {
            try
            {
                _messageFileRepository.Ado.BeginTran();
                //删除原数据
                await _messageFileMongoDbRepository.DeleteAsync(_messagefiles, r => r.MessageId == entity.Id);
                await _messageFileRepository.DeleteAsync(r => r.MessageId == entity.Id);
                if (fileData != null && fileData.Count > 0)
                {
                    var files = new List<MessageFileEntity>();
                    var file = new MessageFileEntity();
                    fileData.ForEach(item =>
                    {
                        file = item.Adapt<MessageFileEntity>();
                        file.Id = YitIdHelper.NextId().ToString();
                        file.MessageId = entity.Id;
                        file.UserId = entity.CreatorUserId;
                        file.CreatorTime = entity.CreatorTime;
                        files.Add(file);
                    });
                    //保存到sqlserver                 
                    var isOk = await _messageFileRepository.Context.Insertable(files).ExecuteCommandAsync();
                    if (!(isOk > 0)) throw YNTKException.Oh(ErrorCode.D7007);
                    //保存到mongodb
                    var succeed = await _messageFileMongoDbRepository.AddListAsync(files, _messagefiles);
                    if (!succeed) throw YNTKException.Oh(ErrorCode.D7008);
                }
                _messageFileRepository.Ado.CommitTran();
            }
            catch (Exception ex)
            {
                _messageFileRepository.Ado.RollbackTran();
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"保存消息相关附件发生异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 删除消息相关附件数据
        /// </summary>
        /// <param name="messageId">消息id</param>
        /// <returns></returns>
        private async Task DeleteMessageFileAsync(string messageId)
        {
            var result = await GetMessageFileListAsync(messageId);
            if (result.Any())
            {
                //删除原数据
                await _messageFileMongoDbRepository.DeleteAsync(_messagefiles, r => r.MessageId == messageId);
                await _messageFileRepository.DeleteAsync(r => r.MessageId == messageId);
                //删除文件
                var deleteFiles = result.Adapt<List<FileListDto>>();
                _fileService.DeleteFiles(deleteFiles);
            }
        }

        /// <summary>
        /// 根据条件删除消息相关附件
        /// </summary>
        /// <param name="where">条件</param>
        /// <returns></returns>
        private async Task DeleteMessageFileAsync(Expression<Func<MessageFileEntity, bool>> where)
        {
            var result = await GetMessageFileListAsync(where);
            if (result.Any())
            {
                //删除原数据
                await _messageFileMongoDbRepository.DeleteAsync(_messagefiles, where);
                await _messageFileRepository.DeleteAsync(where);
                //删除文件
                var deleteFiles = result.Adapt<List<FileListDto>>();
                _fileService.DeleteFiles(deleteFiles);
            }
        }
        #endregion

        #region 消息接收用户
        /// <summary>
        /// 根据条件获取消息接收用户信息
        /// </summary>
        /// <param name="where">条件</param>
        /// <returns></returns>
        [NonAction]
        public async Task<MessageReceiveEntity> GetMessageReceiveAsync(Expression<Func<MessageReceiveEntity, bool>> where)
        {
            var entity= await _messageReceiveMongoDbRepository.GetAsync(_messagereceive, where);
            if (entity == null) entity = await _messageReceiveRepository.FirstOrDefaultAsync(where);
            return entity;
        }

        /// <summary>
        /// 根据条件获取消息接收用户数据
        /// </summary>
        /// <param name="where">条件</param>
        /// <returns></returns>
        [NonAction]
        public async Task<List<MessageReceiveEntity>> GetMessageReceiveListAsync(Expression<Func<MessageReceiveEntity, bool>> where)
        {
            //从mongodb中获取消息接收用户数据
            var result = await _messageReceiveMongoDbRepository.GetListAsync(_messagereceive, where);
            if (!result.Any())
            {
                //从sqlserver数据库中获取消息接收用户数据
                result = await _messageReceiveRepository.Entities.Where(where).ToListAsync();
            }
            return result;
        }

        /// <summary>
        /// 根据条件获取接收用户数量
        /// </summary>
        /// <param name="where">条件</param>
        /// <returns></returns>
        [NonAction]
        public async Task<long> GetCountAsync(Expression<Func<MessageReceiveEntity, bool>> where)
        {
            long count = await _messageReceiveMongoDbRepository.CountAsync(_messagereceive, where);
            if (!(count > 0)) count = await _messageReceiveRepository.CountAsync(where);
            return count;
        }

        /// <summary>
        /// 获取消息接收用户
        /// </summary>
        /// <param name="messageId">消息id</param>
        /// <returns></returns>
        private async Task<List<MessageReceiveEntity>> GetMessageReceiveListAsync(string messageId)
        {
            //从mongodb中获取消息接收用户数据
            var result = await _messageReceiveMongoDbRepository.GetListAsync(_messagereceive, r => r.MessageId == messageId);
            if (!result.Any())
            {
                //从sqlserver数据库中获取消息接收用户数据
                result = await _messageReceiveRepository.Entities
                    .Where(r => r.MessageId == messageId).ToListAsync();
            }
            return result;
        }

        /// <summary>
        /// 保存消息接收用户
        /// </summary>
        /// <param name="message">消息信息</param>
        /// <param name="toUserIds">接收用户id集合</param>
        /// <returns></returns>
        private async Task SaveMessageReceiveAsync(MessageEntity message, List<string> toUserIds)
        {
            try
            {
                _messageReceiveRepository.Ado.BeginTran();
                //删除原数据
                await _messageReceiveMongoDbRepository.DeleteAsync(_messagereceive, r => r.MessageId == message.Id);
                await _messageReceiveRepository.DeleteAsync(r => r.MessageId == message.Id);
                if (toUserIds.Any())
                {
                    var entities = new List<MessageReceiveEntity>()
                    {
                        new MessageReceiveEntity()
                        {
                            Id = YitIdHelper.NextId().ToString(),
                            IsReceive=false,//是否为接收人
                            MessageId = message.Id,
                            OrganizeId = message.OrganizeId,
                            MechanismId = message.MechanismId,
                            Title = message.Title,
                            Type = message.Type,
                            Notice = message.Notice,
                            CreatorTime = message.CreatorTime,
                            SendUserId = message.CreatorUserId,//发送人
                            IsRead =false,//是否阅读
                            ReadCount = 0,//阅读次数
                            UserId=null
                        }
                    };
                    toUserIds.ForEach(userId =>
                    {
                        var entity = new MessageReceiveEntity();
                        entity.Id = YitIdHelper.NextId().ToString();
                        entity.IsReceive = true;//是否为接收人
                        entity.MessageId = message.Id;
                        entity.OrganizeId = message.OrganizeId;
                        entity.MechanismId = message.MechanismId;
                        entity.Title = message.Title;
                        entity.Type = message.Type;
                        entity.Notice = message.Notice;
                        entity.CreatorTime = message.CreatorTime;
                        entity.UserId = userId;//接收用户id
                        entity.IsRead =false;//是否阅读
                        entity.ReadCount = 0;//阅读次数
                        entity.SendUserId = null;//发送人
                        entities.Add(entity);
                    });
                    //保存到sqlserver                 
                    var isOk = await _messageReceiveRepository.Context.Insertable(entities).ExecuteCommandAsync();
                    if (!(isOk > 0)) throw YNTKException.Oh(ErrorCode.D7009);
                    //保存到mongodb
                    var succeed = await _messageReceiveMongoDbRepository.AddListAsync(entities, _messagereceive);
                    if (!succeed) throw YNTKException.Oh(ErrorCode.D7010);
                }
                _messageReceiveRepository.Ado.CommitTran();
            }
            catch (Exception ex)
            {
                _messageReceiveRepository.Ado.RollbackTran();
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"保存消息接收用户发生异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 删除消息接收用户
        /// </summary>
        /// <param name="messageId">消息id</param>
        /// <returns></returns>
        private async Task DeleteMessageReceiveAsync(string messageId)
        {
            var result = await GetMessageReceiveListAsync(messageId);
            if (result.Any())
            {
                //删除原数据
                await _messageReceiveMongoDbRepository.DeleteAsync(_messagereceive, r => r.MessageId == messageId);
                await _messageReceiveRepository.DeleteAsync(r => r.MessageId == messageId);
            }
        }

        /// <summary>
        /// 根据条件删除消息接收用户
        /// </summary>
        /// <param name="where">条件</param>
        /// <returns></returns>
        private async Task DeleteMessageReceiveAsync(Expression<Func<MessageReceiveEntity, bool>> where)
        {
            var result = await GetMessageReceiveListAsync(where);
            if (result.Any())
            {
                //删除原数据
                await _messageReceiveMongoDbRepository.DeleteAsync(_messagereceive, where);
                await _messageReceiveRepository.DeleteAsync(where);
            }
        }
        #endregion


        #region PublicMethod
        /// <summary>
        /// 列表
        /// </summary>
        /// <param name="type">类型</param>
        /// <returns></returns>
        [NonAction]
        public async Task<List<MessageEntity>> GetList(int type)
        {
            return await _messageRepository.Entities.Where(m => m.Type == type && m.DeleteMark == null).ToListAsync();
        }

        /// <summary>
        /// 默认公告(app)
        /// </summary>
        /// <returns></returns>
        [NonAction]
        public string GetInfoDefaultNotice()
        {
            var entity = _messageRepository.Entities.Where(x => x.Type == 1 && x.DeleteMark == null).OrderBy(x=>x.CreatorTime,OrderByType.Desc).First();
            return entity == null ? "" : entity.Title;
        }

        /// <summary>
        /// 默认消息(app)
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        [NonAction]
        public string GetInfoDefaultMessage(string userId)
        {
            var entity = db.Queryable<MessageEntity, MessageReceiveEntity>((a, b) => new JoinQueryInfos(JoinType.Left, a.Id == b.MessageId))
                .Where((a, b) => a.Type == 2 && a.DeleteMark == null && b.UserId == userId).OrderBy(a => a.CreatorTime,OrderByType.Desc).Select(a => a).First();
            return entity == null ? "" : entity.Title;
        }

        /// <summary>
        /// 消息已读（单条）
        /// </summary>
        /// <param name="userId">当前用户</param>
        /// <param name="messageId">消息主键</param>
        [NonAction]
        public async Task MessageRead(string userId, string messageId)
        {
            await db.Updateable<MessageReceiveEntity>().SetColumns(it => it.ReadCount == it.ReadCount + 1).SetColumns(x => new MessageReceiveEntity()
            {
                IsRead = true,
                ReadTime = DateTime.Now
            }).Where(x => x.UserId == userId && x.MessageId == messageId).ExecuteCommandAsync();

        }

        /// <summary>
        /// 消息已读（全部）
        /// </summary>
        /// <param name="id">id</param>
        [NonAction]
        public async Task MessageRead(string id)
        {
            try
            {
                db.BeginTran();
                var whereParams= LinqExpression.And<MessageReceiveEntity>();
                whereParams = whereParams.And(x => x.UserId == _userManager.UserId && x.IsRead == false);
                if(id.IsNotEmptyOrNull())
                    whereParams = whereParams.And(x => x.MessageId ==id);
                await db.Updateable<MessageReceiveEntity>().SetColumns(it => it.ReadCount == it.ReadCount + 1).SetColumns(x => new MessageReceiveEntity()
                {
                    IsRead = true,
                    ReadTime = DateTime.Now
                }).Where(whereParams).ExecuteCommandAsync();

                db.CommitTran();
            }
            catch (Exception e)
            {
                db.RollbackTran();
            }
        }

        /// <summary>
        /// 删除记录
        /// </summary>
        /// <param name="userId">当前用户</param>
        /// <param name="messageIds">消息Id</param>
        [NonAction]
        public async Task<int> DeleteRecord(string userId, List<string> messageIds)
        {
            return await _messageReceiveRepository.DeleteAsync(m => m.UserId == userId && messageIds.Contains(m.MessageId));
        }

        /// <summary>
        /// 获取公告未读数量
        /// </summary>
        /// <param name="userId">用户id</param>
        /// <returns></returns>
        [NonAction]
        public int GetUnreadNoticeCount(string userId)
        {
            return db.Queryable<MessageEntity, MessageReceiveEntity>((m, mr) => 
            new JoinQueryInfos(JoinType.Left, m.Id == mr.MessageId))
                .Select((m, mr) => new { mr.Id, mr.UserId, mr.IsRead, m.Type, m.DeleteMark })
                .MergeTable().Where(x => x.Type != 3 && x.DeleteMark == null && x.UserId == userId && 
                x.IsRead == false).ToList().Count;
        }

        /// <summary>
        /// 获取消息未读数量
        /// </summary>
        /// <param name="userId">用户id</param>
        /// <returns></returns>
        [NonAction]
        public int GetUnreadMessageCount(string userId)
        {
            return db.Queryable<MessageEntity, MessageReceiveEntity>((m, mr) => new JoinQueryInfos(JoinType.Left, m.Id == mr.MessageId)).Select((m, mr) => new { mr.Id, mr.UserId, mr.IsRead, m.Type, m.DeleteMark }).MergeTable().Where(x => x.Type == 2 && x.DeleteMark == null && x.UserId == userId && x.IsRead == false).ToList().Count;
        }

        /// <summary>
        /// 发送站内消息(系统消息)
        /// </summary>
        /// <param name="toUserIds">接收用户id集合</param>
        /// <param name="title">标题</param>
        /// <param name="bodyText">正文</param>
        [NonAction]
        public async Task SentMessage(List<string> toUserIds, string title, string bodyText = null)
        {
            try
            {
                if (toUserIds == null || toUserIds.Count <= 0) return;
                MessageEntity entity = new MessageEntity();
                entity.Id = YitIdHelper.NextId().ToString();
                entity.Title = title;
                entity.BodyText = bodyText;
                entity.Type = 2;//消息类型(0.平台公告 1.通知公告 2.系统消息 3.私信消息)
                entity.Notice =2;//通知公告接收对象类型(0.所有人 1.本机构 2.指定人员)
                entity.ToUserIds = string.Join(',', toUserIds);//收件用户id,多个用户按逗号分割
                entity.OrganizeId = _userManager.OrganizeId;
                entity.MechanismId = _userManager.MechanismId;
                entity.CreatorUserId = _userManager.UserId;
                entity.CreatorTime= DateTime.Now;
                entity.LastModifyTime = entity.CreatorTime;
                entity.LastModifyUserId = _userManager.UserId;
                entity.IsRead = false;//是否阅读
                entity.ReadCount = 0;//阅读次数
                entity.ReadUserCount = 0;//已阅读用户数量

                //保存系统消息到sqlserver
                var isOk = await _messageRepository.Context.Insertable(entity)
                   .CallEntityMethod(m => m.Creator()).ExecuteReturnEntityAsync();
                _ = isOk ?? throw YNTKException.Oh(ErrorCode.D7016);

                //保存系统消息到mongodb
                entity = isOk;
                var result = await _messageMongoDbRepository.AddAsync(entity, _message);
                if (!result) throw YNTKException.Oh(ErrorCode.D7017);

                //保存系统消息接收用户             
                await SaveMessageReceiveAsync(entity, toUserIds);

                //消息推送 - PC端
                foreach (var item in WebSocketClientCollection._clients)
                {
                    if (toUserIds.Contains(item.UserId))
                    {
                        await item.SendMessageAsync(new { method = "messagePush", userId = _userManager.UserId, 
                            toUserId = toUserIds, title = entity.Title, unreadNoticeCount = 1 }.Serialize());
                    }
                }
                //消息推送 - APP
                // GetuiAppPushHelper.Instance.SendNotice(userInfo.TenantId, toUserIds, "系统消息", entity.F_Title, "2");
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"发送站内消息(系统消息)发生异常：{ex.Message}");
            }
        }
        #endregion
    }
}
